package com.kk.audioeffect;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Build;
import android.os.SystemClock;
import android.text.method.KeyListener;
import android.util.Log;

import androidx.annotation.RequiresApi;

import java.io.File;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

/**
 * author:wk
 * date:2023/12/5
 * 包名:com.kk.audioeffect
 */
public class PCMPlayer implements IPlayControl {

    private final static String TAG = "PCMPlayer";

    private IMusicListener mMusicListener = null;


    private final static int MAX_PLAY_BUFFER_SIZE = 20;

    private int samplate = 44100;
    private int channels = 2;
    private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    private String mFilePath = "";

    enum Status {
        Status_Idle,
        Status_Prepareing,
        Status_Parpared,
        Status_Playing,
        Status_Pause,
        Status_Stop,
    }

    private Status mStatus = Status.Status_Idle;

    private PCMPlayer(int samplate, int channels, int audioFormat) {
        this.samplate = samplate;
        this.channels = channels;
        this.audioFormat = audioFormat;

        initPcmPlay();
    }

    public void setMusicListener(IMusicListener mMusicListener) {
        this.mMusicListener = mMusicListener;
    }

    @Override
    public void start() {
        if (mStatus == Status.Status_Parpared || mStatus == Status.Status_Pause) {
            //播放
            mStatus = Status.Status_Playing;
            synchronized (mPlayList) {
                mPlayList.notify();
            }
        } else {
            Log.e(TAG, "start: 当前状态不对 " + mStatus);
        }
    }

    @Override
    public void pause() {

        if (mStatus == Status.Status_Playing) {
            mStatus = Status.Status_Pause;
        } else {
            Log.e(TAG, "pause: 当前状态不对" + mStatus);
        }
    }

    @Override
    public void stop() {
        if (mStatus != Status.Status_Stop) {
            mStatus = Status.Status_Stop;
        } else {
            Log.e(TAG, "stop: 当前状态不对" + mStatus);
        }
    }

    @Override
    public void reset() {
        mStatus = Status.Status_Idle;
    }

    @Override
    public boolean isPlayinng() {
        return mStatus == Status.Status_Playing;
    }

    @Override
    public boolean isPause() {
        return mStatus == Status.Status_Pause;
    }

    private void notify_onPrepared() {
        if (mMusicListener != null) {
            mMusicListener.onPrepared(this);
        }
    }

    @Override
    public void prepare() {
        if (mStatus == Status.Status_Idle) {
            mStatus = Status.Status_Prepareing;

            new Thread(new Runnable() {
                @Override
                public void run() {

                    try {
                        RandomAccessFile randomAccessFile = new RandomAccessFile(mFilePath, "r");
                        mStatus = Status.Status_Parpared;
                        notify_onPrepared();

                        int readBytes = 0;
                        byte[] buf = new byte[2048];
                        while ((readBytes = randomAccessFile.read(buf, 0, 2048)) > 0) {
                            addPlayBuffer(buf, readBytes);
                        }

                        Log.i(TAG, "run: 播放完成...");

                    } catch (Exception e) {
                        e.printStackTrace();

                        if (mMusicListener != null) {
                            mMusicListener.onError(PCMPlayer.this, -1);
                        }

                        mStatus = Status.Status_Stop;
                    }
                }
            }).start();

        } else {
            Log.e(TAG, "prepare: 当前状态不对" + mStatus);
        }
    }


    private List<AudioBuffer> freeList = new LinkedList<>();

    private void addPlayBuffer(byte[] buff, int size) {
        AudioBuffer buffer = null;
       // Log.i(TAG, "addPlayBuffer: 加入播放队列"+SystemClock.elapsedRealtime());
        synchronized (freeList) {
            if (freeList.isEmpty()) {
                buffer = new AudioBuffer();
            } else {
                buffer = freeList.remove(0);
            }
        }

        buffer.update(buff, size);

        synchronized (mPlayList) {
            mPlayList.add(buffer);

            while(mPlayList.size() > MAX_PLAY_BUFFER_SIZE) {
                try {
                  //  Log.i(TAG, "addPlayBuffer: full "+SystemClock.elapsedRealtime());
                    mPlayList.wait(100);
                    mPlayList.notify();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            mPlayList.notify();
        }
    }

    //    设置路径
    public void setFilePath(String filePath) {
        this.mFilePath = filePath;
    }

    public static PCMPlayer create(int samplate, int channels, int audioFormat) {
        PCMPlayer pcmPlayer = new PCMPlayer(samplate, channels, audioFormat);
        return pcmPlayer;
    }


    class AudioBuffer {
        byte[] buff = null;
        int buff_size = 0;
        int caption = 0;


        void update(byte[] src, int size) {
            if (buff == null) {
                buff = new byte[size];
                caption = size;
            }

            if (caption < size) {
                buff = null;
                buff = new byte[size];
                caption = size;
            }
            this.buff_size = size;
            System.arraycopy(src, 0, buff, 0, size);

        }
    }


    List<AudioBuffer> mPlayList = new LinkedList<>();


    long    mRenderBufferCount = 0;
    long    mStartTimes = 0;




    static double   calcPts(long bufferCount)
    {
       return  bufferCount/(44100*2*2/1000.0f);
    }
    void initPcmPlay() {
        new Thread(new Runnable() {
            @RequiresApi(api = Build.VERSION_CODES.N)
            @Override
            public void run() {


                native_bass(10);
                Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
                int bufferSizeInBytes = AudioTrack.getMinBufferSize(samplate, AudioFormat.CHANNEL_OUT_STEREO, audioFormat);
                AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC
                        , samplate
                        , AudioFormat.CHANNEL_OUT_STEREO
                        , audioFormat
                        , bufferSizeInBytes
                        , AudioTrack.MODE_STREAM);

                audioTrack.play();

                AudioBuffer buffer = null;


                while (true) {

                    buffer = null;
                    if (mStatus == Status.Status_Playing) {
                        if(mRenderBufferCount==0)
                        {
                            mStartTimes = SystemClock.elapsedRealtime();
                        }
                        try {
                            synchronized (mPlayList) {
                                if (mPlayList.isEmpty()) {
                                    mPlayList.wait();
                                }

                                if (mPlayList.isEmpty()) {
                                    Thread.sleep(100);
                                    continue;
                                }
                                buffer = mPlayList.remove(0);
                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        }


                       long cur_pts =   SystemClock.elapsedRealtime() - mStartTimes;
                        while ((calcPts(mRenderBufferCount) - cur_pts>200))
                        {
                            try {
                                Thread.sleep(20);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            cur_pts =   SystemClock.elapsedRealtime()/1000 - mStartTimes;
                        }

                        Log.i(TAG, "run: 准备播放 "+ SystemClock.elapsedRealtime()+"  "+buffer.buff_size+"  count:"+audioTrack.getUnderrunCount()+"  pts:"+cur_pts+ "   bufPts"+calcPts(mRenderBufferCount)+"  mRenderBufferCount:"+mRenderBufferCount);

                        native_process(buffer.buff,buffer.buff_size);
                        if (buffer != null) {
                            audioTrack.write(buffer.buff, 0, buffer.buff_size);
                        }
                        mRenderBufferCount+= buffer.buff_size;



                        synchronized (freeList) {
                            freeList.add(buffer);
                        }

                    } else {


                        try {
                            Thread.sleep(500);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }

            }
        }).start();
    }


    public static native void native_bass(float bass);

    public static native void native_amp(float db);

    public static native void native_init(int samplate);
    public static native int native_process(byte[]bytes,int len);

    public static native void native_upate_bands_prem(int bandIndex, float db);

    public static native void native_upate_preset(String preset);
}
